<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button>点击</button>
    <script>
      const button = document.querySelector("button");
      class Subject {
        constructor() {
          this.listener = null;
          this.to = null; // 标识 debounce 的定时器
          this.canRun = true; // 标识能否运行
          this.arr = []; // 信息列表
        }
        // 延迟
        publishDelay(val) {
          if (this.listener) {
            setTimeout(() => {
              // 控制它 1 秒以后才收听
              this.listener(val);
            }, 1000);
          }
        }
        // 防抖 debounce
        publishDebounce(val) {
          if (this.listener) {
            // 在下一次 publish 调用时，清除上一次的定时器
            clearTimeout(this.to);
            this.to = setTimeout(() => {
              this.listener(val);
            }, 1000);
          }
        }


        // 打包 zip
        publishZip(val) {
          if (this.listener) {
            // 一次性收集 4 个信息，然后一次性发送
            this.arr.push(val);
            if (this.arr.length === 4) {
              this.listener(this.arr);
              this.arr = [];
            }
          }
        }


        // 节流 throttle
        publishThrottle(val) {
          if (this.listener) {
            // 一段时间内，只允许执行 1 次
            if (this.canRun) {
              // 能执行，直接执行
              this.listener(val);
              // 接下来这一秒钟，不允许执行
              this.canRun = false;
              setTimeout(() => {
                this.canRun = true;
              }, 1000);
            }
          }
        }
        subscribe(cb) {
          this.listener = cb;
        }
      }


      const subject = new Subject();


      subject.subscribe((msg) => {
        console.log(msg);
      });


      button.addEventListener("click", () => {
        subject.publishThrottle("hello");
      });
      window.addEventListener("keydown", (e) => {
        subject.publishZip(e.key);
      });
    </script>
  </body>
</html>